2.4.1. Hystrix

Hystrix

在Spring Cloud中使用了Netflix开发的Hystrix来实现熔断器。下面我们依然通过几个简单的代码示例,进入Hystrix的学习:

通用方式使用Hystrix

代码示例:

新建一个Maven项目,在pom.xml中添加如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <artifactId>microservice-consumer-movie-ribbon-with-hystrix</artifactId>
  <packaging>jar</packaging>

  <parent>
    <groupId>com.itmuch.cloud</groupId>
    <artifactId>spring-cloud-microservice-study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>

    <!-- 整合ribbon -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- 整合hystrix -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
  </dependencies>
</project>

启动类:MovieRibbonHystrixApplication.java,使用@EnableCircuitBreaker注解开启断路器功能:

/**
 * 使用@EnableCircuitBreaker注解开启断路器功能
 * @author eacdy
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class MovieRibbonHystrixApplication {
  /**
   * 实例化RestTemplate,通过@LoadBalanced注解开启均衡负载能力.
   * @return restTemplate
   */
  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

  public static void main(String[] args) {
    SpringApplication.run(MovieRibbonHystrixApplication.class, args);
  }
}

实体类:User.java

public class User {
  private Long id;
  private String username;
  private Integer age;
  ...
  // getters and setters
}

Hystrix业务类:RibbonHystrixService.java,使用@HystrixCommand注解指定当该方法发生异常时调用的方法

@Service
public class RibbonHystrixService {
  @Autowired
  private RestTemplate restTemplate;
  private static final Logger LOGGER = LoggerFactory.getLogger(RibbonHystrixService.class);

  /**
   * 使用@HystrixCommand注解指定当该方法发生异常时调用的方法
   * @param id id
   * @return 通过id查询到的用户
   */
  @HystrixCommand(fallbackMethod = "fallback")
  public User findById(Long id) {
    return this.restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
  }

  /**
   * hystrix fallback方法
   * @param id id
   * @return 默认的用户
   */
  public User fallback(Long id) {
    RibbonHystrixService.LOGGER.info("异常发生,进入fallback方法,接收的参数:id = {}", id);
    User user = new User();
    user.setId(-1L);
    user.setUsername("default username");
    user.setAge(0);
    return user;
  }
}

controller:RibbonHystrixController.java

@RestController
public class RibbonHystrixController {
  @Autowired
  private RibbonHystrixService ribbonHystrixService;

  @GetMapping("/ribbon/{id}")
  public User findById(@PathVariable Long id) {
    return this.ribbonHystrixService.findById(id);
  }
}

application.yml

server:
  port: 8011
spring:
  application:
    name: microservice-consumer-movie-ribbon-with-hystrix
eureka:
  client:
    serviceUrl:
      defaultZone: http://discovery:8761/eureka/
  instance:
    hostname: ribbon          # 此处,preferIpAddress不设置或者设为false,不能设为true,否则影响turbine的测试。turbine存在的问题:eureka.instance.hostname一致时只能检测到一个节点,会造成turbine数据不完整

验证:

  1. 启动注册中心:microservice-discovery-eureka

  2. 启动服务提供方:microservice-provider-user

  3. 启动服务消费方:microservice-consumer-movie-ribbon-with-hystrix

  4. 访问:http://localhost:8011/ribbon/1,获得结果:{"id":1,"username":"Tom","age":12}

  5. 关闭服务提供方:microservice-provider-user,访问http://localhost:8011/ribbon/1,获得结果:{"id":-1,"username":"default username","age":0},另外日志打印:c.i.c.s.u.service.RibbonHystrixService : 异常发生,进入fallback方法,接收的参数:id = 1

注意:

  1. 本示例代码在microservice-consumer-movie-ribbon基础上修改而来
  2. 如对本示例涉及的知识点有疑难,请查看上一章《服务消费者》

代码地址(任选其一):

  1. http://git.oschina.net/itmuch/spring-cloud-study/tree/master/microservice-consumer-movie-ribbon-with-hystrix
  2. https://github.com/eacdy/spring-cloud-study/tree/master/microservice-consumer-movie-ribbon-with-hystrix

Feign使用Hystrix

代码示例

在Feign中使用Hystrix是非常简单的事情,因为Feign已经集成了Hystrix。我们使用microservice-consumer-movie-feign-with-hystrix项目的代码做一点修改,将其中的UserClient.java修改为如下即可:

/**
 * 使用@FeignClient注解的fallback属性,指定fallback类
 * @author eacdy
 */
@FeignClient(name = "microservice-provider-user", fallback = HystrixClientFallback.class)
public interface UserFeignHystrixClient {
  @RequestMapping("/{id}")
  public User findByIdFeign(@RequestParam("id") Long id);

  /**
   * 这边采取了和Spring Cloud官方文档相同的做法,将fallback类作为内部类放入Feign的接口中,当然也可以单独写一个fallback类。
   * @author eacdy
   */
  @Component
  static class HystrixClientFallback implements UserFeignHystrixClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(HystrixClientFallback.class);

    /**
     * hystrix fallback方法
     * @param id id
     * @return 默认的用户
     */
    @Override
    public User findByIdFeign(Long id) {
      HystrixClientFallback.LOGGER.info("异常发生,进入fallback方法,接收的参数:id = {}", id);
      User user = new User();
      user.setId(-1L);
      user.setUsername("default username");
      user.setAge(0);
      return user;
    }
  }
}

这样就完成了,是不是很简单呢?测试过程类似通用方式。

注意:

  1. 本示例代码在microservice-consumer-movie-feign基础上修改而来
  2. 如对本示例涉及的知识点有疑难,请查看上一章《服务消费者》

代码地址(任选其一)

  1. http://git.oschina.net/itmuch/spring-cloud-study/tree/master/microservice-consumer-movie-feign-with-hystrix
  2. https://github.com/eacdy/spring-cloud-study/tree/master/microservice-consumer-movie-feign-with-hystrix

参考文档:

  1. https://msdn.microsoft.com/en-us/library/dn589784.aspx
  2. http://martinfowler.com/bliki/CircuitBreaker.html
  3. http://particular.net/blog/protect-your-software-with-the-circuit-breaker-design-pattern
  4. https://github.com/Netflix/Hystrix/wiki/How-it-Works#flow-chart
  5. https://segmentfault.com/a/1190000005988895

results matching ""

    No results matching ""